home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / muzsrc1.zip / DISPLAY.CPP < prev    next >
C/C++ Source or Header  |  1992-07-21  |  17KB  |  483 lines

  1. // **********************************************
  2. // File: DISPLAY.CPP
  3. // The display module
  4.  
  5. #include "muzika.h"
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <values.h>
  9.  
  10. HWND hEditWnd;                    // The edit window handle
  11. HCURSOR hEditCursor;              // The handle of the edit window cursor
  12. int currStaffHeight;              // Height of the currently displayed staff
  13. STAFFLOC staffLoc;                // Current staff location within multiple
  14. int staffX, staffY;               // Coordinates of the current staff
  15. int scoreMultiplicity, scoreStaves; // Parameters for the score display
  16. int scoreFirstStaff, scoreFirstPart; // Parameters for the score display
  17.  
  18. // **********************************************
  19. // Following are the Edit window functions
  20.  
  21. // **********************************************
  22. // RegisterEditClass registers the Edit window class
  23. // during the first-instance initialization (called by
  24. // InitMainFirst in MAIN.CPP).
  25.  
  26. void RegisterEditClass(HANDLE hInstance)
  27. {
  28.   WNDCLASS wc;
  29.  
  30.   // Register the edit window class
  31.   wc.lpszClassName = "MUZIKA_edit";
  32.   wc.hInstance = hInstance;
  33.   wc.lpfnWndProc = EditWindowProc;
  34.   wc.hCursor = NULL;
  35.   wc.hIcon = NULL;
  36.   wc.lpszMenuName = NULL;
  37.   wc.hbrBackground = COLOR_APPWORKSPACE+1;
  38.   wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  39.   wc.cbClsExtra = 0;
  40.   wc.cbWndExtra = 0;
  41.   RegisterClass(&wc);
  42. }
  43.  
  44. // **********************************************
  45. // CreateEditWindow creates and displays an edit window
  46. // (this is the window where the edited score is displayed).
  47.  
  48. void CreateEditWindow(HANDLE hInstance)
  49. {
  50.   // Get the main window extents
  51.   RECT mainExt;
  52.   GetClientRect(hMainWnd, &mainExt);
  53.  
  54.   // Create and display the edit window
  55.   hEditWnd = CreateWindow("MUZIKA_edit",
  56.     NULL,
  57.     WS_CHILDWINDOW | WS_VSCROLL,
  58.     73, 37,
  59.     mainExt.right-72, mainExt.bottom-36,
  60.     hMainWnd,
  61.     NULL,
  62.     hInstance,
  63.     NULL);
  64.   ShowScrollBar(hEditWnd, SB_VERT, FALSE);
  65.   ShowWindow(hEditWnd, SW_SHOWNA);
  66.  
  67.   // Set the initial cursor
  68.   hEditCursor = LoadCursor(NULL, IDC_ARROW);
  69. }
  70.  
  71. // **********************************************
  72. // EditWindowProc is the edit window procedure, which responds to messages
  73. // intended for the edit window. The messages processed are described within.
  74.  
  75. long FAR PASCAL EditWindowProc(
  76.   HWND hWnd, unsigned message, WORD wParam, LONG lParam)
  77. {
  78.   static int Xfrom, Xto, Y, Yfrom, Yto;
  79.   static enum {NEWCONTINUOUS, MOVEOBJECT, MOVESTAFF} capture;
  80.  
  81.   // Check message type
  82.   switch(message) {
  83.     case WM_PAINT:
  84.       // Process a WM_PAINT message, indicating that the window
  85.       // should be repainted.
  86.       PaintEditWindow(hWnd);
  87.       break;
  88.  
  89.     case WM_MOUSEMOVE:
  90.       // Process a WM_MOUSEMOVE message, indicating that the cursor
  91.       // has moved in the edit window region; the cursor shape should
  92.       // be changed to the current symbol shape.
  93.       SetCursor(hEditCursor);
  94.       break;
  95.  
  96.     case WM_LBUTTONDOWN:
  97.       // Process a WM_LBUTTONDOWN message, indicating that the user
  98.       // has clicked the left mouse button. According to what the
  99.       // current edit symbol is, an editing action is performed.
  100.       if (melodyExists)
  101.         if (!scoreDisplay)
  102.           switch (GetActiveSymbol()) {
  103.             case PENCIL:
  104.               // The current symbol is the pencil on a staff:
  105.               // insert a new staff at the current position
  106.               NewMultipleStaff(MAKEPOINT(lParam).y);
  107.               break;
  108.  
  109.             case ERASER:
  110.               // The current symbol is the eraser:
  111.               // erase the symbols at the current cursor position
  112.               DeleteMusicalObject(MAKEPOINT(lParam).x, MAKEPOINT(lParam).y);
  113.               break;
  114.  
  115.             case HAND:
  116.               // The current symbol is the hand:
  117.               // capture the mouse until the left button is released,
  118.               // then move the objects to their new place.
  119.               Xfrom = MAKEPOINT(lParam).x;
  120.               Yfrom = MAKEPOINT(lParam).y;
  121.               SetCapture(hEditWnd);
  122.               capture = MOVEOBJECT;
  123.               break;
  124.  
  125.             default:
  126.               // The current symbol is one of the musical object symbols:
  127.               // insert the appropriate object at the current position
  128.               SymbolClass *currentSymbol = GetCurrentSymbol();
  129.               switch (currentSymbol->GetType()) {
  130.                 case POINTOBJECT:
  131.                   // The symbol corresponds to a point object:
  132.                   // just insert the object in the staff
  133.                   NewPointObject(currentSymbol,
  134.                     MAKEPOINT(lParam).x, MAKEPOINT(lParam).y);
  135.                   break;
  136.  
  137.                 case CONTINUOUSOBJECT:
  138.                   // The symbol corresponds to a continuous object:
  139.                   // capture the mouse until the left button is released,
  140.                   // then create the object between its two extents.
  141.                   Xfrom = MAKEPOINT(lParam).x;
  142.                   Y = MAKEPOINT(lParam).y;
  143.                   SetCapture(hEditWnd);
  144.                   capture = NEWCONTINUOUS;
  145.                   break;
  146.               }
  147.           }
  148.         else
  149.           // No editing is allowed on a score display
  150.           MessageBox(hWnd, "Cannot edit a score display", NULL,
  151.             MB_ICONSTOP | MB_OK);
  152.       break;
  153.  
  154.     case WM_LBUTTONUP:
  155.       // Process a WM_LBUTTONUP message, indicating that the
  156.       // left mouse button has been released. In case the mouse cursor
  157.       // was captured (presumably because of an operation that required
  158.       // two points to operate), release the capture and complete
  159.       // the operation.
  160.       if (GetCapture() == hEditWnd) {
  161.         switch (capture) {
  162.           case NEWCONTINUOUS:
  163.             // The capture was due to insertion of a continuous object:
  164.             // insert a new continuous object between the two points
  165.             Xto = MAKEPOINT(lParam).x;
  166.             if (Xto < Xfrom) {
  167.               int temp = Xto;
  168.               Xto = Xfrom;
  169.               Xfrom = temp;
  170.             }
  171.             if (Xto != Xfrom)
  172.               NewContinuousObject(GetCurrentSymbol(), Xfrom, Xto, Y);
  173.             break;
  174.  
  175.           case MOVEOBJECT:
  176.             // The capture was due to an object moving operation:
  177.             // move a musical object to its new place
  178.             Xto = MAKEPOINT(lParam).x;
  179.             Yto = MAKEPOINT(lParam).y;
  180.             MoveMusicalObject(Xfrom, Yfrom, Xto, Yto);
  181.             break;
  182.  
  183.           case MOVESTAFF:
  184.             // The capture was due to a staff moving operation:
  185.             // move the staff to its new place
  186.             Yto = MAKEPOINT(lParam).y;
  187.             MoveStaff(Yfrom, Yto);
  188.             break;
  189.         }
  190.         ReleaseCapture();
  191.       }
  192.       break;
  193.  
  194.     case WM_LBUTTONDBLCLK:
  195.       // Process a WM_LBUTTONDBLCLK, indicating that the user has
  196.       // double-clicked the left mouse button. According to what the
  197.       // current edit symbol is, an editing action is performed.
  198.       if (melodyExists)
  199.         if (!scoreDisplay)
  200.           switch(GetActiveSymbol()) {
  201.             case ERASER:
  202.               // The current symbol is the eraser:
  203.               // erase the multiple staff
  204.               DeleteMultipleStaff(MAKEPOINT(lParam).y);
  205.               break;
  206.  
  207.             case HAND:
  208.               // The current symbol is the hand:
  209.               // capture the mouse until the left button is released,
  210.               // then move the staff to its new place.
  211.               Yfrom = MAKEPOINT(lParam).y;
  212.               SetCapture(hEditWnd);
  213.               capture = MOVESTAFF;
  214.               break;
  215.           }
  216.       break;
  217.  
  218.     case WM_VSCROLL:
  219.       // Process a WM_VSCROLL message, indicating that the user
  220.       // has clicked on the scroll bar. The screen should be updated
  221.       // according to the new position of the scroll bar thumb.
  222.       unsigned newY = GetScrollPos(hEditWnd, SB_VERT);
  223.       int minScroll, maxScroll;
  224.       GetScrollRange(hEditWnd, SB_VERT, &minScroll, &maxScroll);
  225.       RECT editRect;
  226.       GetClientRect(hEditWnd, &editRect);
  227.  
  228.       // Process the various possibilities of the scroll bar notification
  229.       switch (wParam) {
  230.         case SB_BOTTOM:
  231.           SetScrollPos(hEditWnd, SB_VERT, maxScroll, TRUE);
  232.           break;
  233.  
  234.         case SB_LINEDOWN:
  235.           SetScrollPos(hEditWnd, SB_VERT,
  236.             newY+(scoreDisplay ? 1 : pixelsPerStaff), TRUE);
  237.           break;
  238.  
  239.         case SB_LINEUP:
  240.           SetScrollPos(hEditWnd, SB_VERT,
  241.             newY-(scoreDisplay ? 1 : pixelsPerStaff), TRUE);
  242.           break;
  243.  
  244.         case SB_PAGEDOWN:
  245.           SetScrollPos(hEditWnd, SB_VERT,
  246.             newY+editRect.bottom/(scoreDisplay ? pixelsPerStaff : 1), TRUE);
  247.           break;
  248.  
  249.         case SB_PAGEUP:
  250.           SetScrollPos(hEditWnd, SB_VERT,
  251.             newY-editRect.bottom/(scoreDisplay ? pixelsPerStaff : 1), TRUE);
  252.           break;
  253.  
  254.         case SB_THUMBPOSITION:
  255.           SetScrollPos(hEditWnd, SB_VERT, LOWORD(lParam), TRUE);
  256.           break;
  257.  
  258.         case SB_TOP:
  259.           SetScrollPos(hEditWnd, SB_VERT, 0, TRUE);
  260.           break;
  261.  
  262.         case SB_ENDSCROLL:
  263.           if (scoreDisplay)
  264.             scoreFirstStaff = newY;
  265.           else
  266.             ((Part *) &melody.part[displayedPart])->SetPartY(newY);
  267.           InvalidateRect(hEditWnd, NULL, TRUE);
  268.           break;
  269.       }
  270.       break;
  271.  
  272.     default:
  273.       // Unrecognized message: just let Windows take care of it.
  274.       return DefWindowProc(hWnd, message, wParam, lParam);
  275.   }
  276.  
  277.   return 0L;
  278. }
  279.  
  280. // **********************************************
  281. // PaintEditWindow is the edit window painting function,
  282. // activated whenever the edit window receives a WM_PAINT message.
  283. // It redraws the edit window, including staves and objects.
  284.  
  285. void PaintEditWindow(HWND hWnd)
  286. {
  287.   PAINTSTRUCT ps;
  288.   HDC hDC;
  289.  
  290.   // Obtain a display context
  291.   hDC = BeginPaint(hWnd, &ps);
  292.  
  293.   // Draw the page according to the current settings
  294.   if (melodyExists) {
  295.     if (!scoreDisplay) {
  296.       // Display a single part
  297.       Part &p = *((Part *) &melody.part[displayedPart]);
  298.       int firstStaff = 0, lastStaff = 0;
  299.  
  300.       // Display the page
  301.       for (int index = 0; index < p.staff.number(); ++index) {
  302.         int firstY, lastY;
  303.         if (index % p.multiplicity() == 0) {
  304.           firstY = -1;
  305.           lastY = MAXINT-24;
  306.         }
  307.         Staff &s = *((Staff *) &p.staff[index]);
  308.  
  309.         // Draw the staff itself
  310.         if (s.Draw(hDC, p.GetPartY(), TRUE)) {
  311.           if (!firstStaff) firstStaff = index+p.multiplicity();
  312.           lastStaff = index+p.multiplicity();
  313.           staffX = s.X();
  314.           staffY = s.Y()-p.GetPartY();
  315.  
  316.           // Check whether first or last staff in a group
  317.           staffLoc = MIDSTAFF;
  318.           if (index % p.multiplicity() == 0) {
  319.             firstY = staffY;
  320.             staffLoc = FIRSTSTAFF;
  321.           }
  322.           if ((index+1) % p.multiplicity() == 0) {
  323.             lastY = staffY;
  324.             staffLoc = LASTSTAFF;
  325.           }
  326.           if (p.multiplicity() == 1)
  327.             staffLoc = SINGLESTAFF;
  328.           currStaffHeight = (index+1 < p.staff.number()) ?
  329.             ((Staff *) &p.staff[index+1])->Y()-s.Y() : pixelsPerStaff;
  330.  
  331.           // Draw the point objects inside the staff
  332.           IndexedList &pointList = s.pointObject;
  333.           for (int i = 0; i < pointList.number(); ++i)
  334.             ((PointObject *) &pointList[i])->Draw(hDC);
  335.  
  336.           // Draw the continuous objects inside the staff
  337.           IndexedList &contList = s.continuousObject;
  338.           for (i = 0; i < contList.number(); ++i)
  339.             ((ContinuousObject *) &contList[i])->Draw(hDC);
  340.         }
  341.  
  342.         // Check if the multiple staff is complete
  343.         if ((index+1)%p.multiplicity() == 0) {
  344.           if (firstY != -1 || lastY != MAXINT-24) {
  345.             // Draw the connecting lines of a multiple staff
  346.             MoveTo(hDC, s.X(), firstY);
  347.             LineTo(hDC, s.X(), lastY+24);
  348.             MoveTo(hDC, s.X()+s.width()-1, firstY);
  349.             LineTo(hDC, s.X()+s.width()-1, lastY+24);
  350.           }
  351.  
  352.           // Show the marked block
  353.           int i = index/p.multiplicity()*p.multiplicity();
  354.           if (i >= markBeginStaff && i <= markEndStaff) {
  355.             int markFrom, markTo;
  356.             if (i == markBeginStaff)
  357.               markFrom = markBeginX-pixelsPerObject/2;
  358.             if (i > markBeginStaff)
  359.               markFrom = 0;
  360.             if (i == markEndStaff)
  361.               markTo = markEndX+pixelsPerObject/2;
  362.             if (i < markEndStaff)
  363.               markTo = s.width();
  364.             PatBlt(hDC, markFrom+s.X(),
  365.               ((Staff *) &p.staff[i])->Y()-p.GetPartY(),
  366.               markTo-markFrom, s.Y()+25-((Staff *) &p.staff[i])->Y(),
  367.               DSTINVERT);
  368.           }
  369.         }
  370.       }
  371.  
  372.       // Display the status information
  373.       char strnum[15];
  374.       HDC hStatusDC = GetDC(hMainWnd);
  375.       HBRUSH hBrush, hOldBrush;
  376.       hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  377.       hOldBrush = SelectObject(hStatusDC, hBrush);
  378.       Rectangle(hStatusDC, 108, -1, GetSystemMetrics(SM_CXSCREEN), 37);
  379.       SetBkColor(hStatusDC, GetSysColor(COLOR_WINDOW));
  380.       SetTextAlign(hStatusDC, TA_UPDATECP);
  381.       MoveTo(hStatusDC, 110, 2);
  382.       TextOut(hStatusDC, 0, 0, "Current part: ", 14);
  383.       TextOut(hStatusDC, 0, 0, p.name(), strlen(p.name()));
  384.       TextOut(hStatusDC, 0, 0, ", Staves ", 9);
  385.       sprintf(strnum, "%d-%d",
  386.         firstStaff/p.multiplicity(), lastStaff/p.multiplicity());
  387.       TextOut(hStatusDC, 0, 0, strnum, strlen(strnum));
  388.       SelectObject(hStatusDC, hOldBrush);
  389.       DeleteObject(hBrush);
  390.       ReleaseDC(hMainWnd, hStatusDC);
  391.     }
  392.     else {
  393.       // Display score
  394.       int line = 0;
  395.       int staffLeftX = 32;
  396.       int staffRightX = 32+melody.GetStaffWidth();
  397.       BOOL screenFull = FALSE;
  398.  
  399.       for (int scoreIndex = scoreFirstStaff;
  400.         scoreIndex < scoreStaves && !screenFull; ++scoreIndex) {
  401.         // Draw a multiple staff
  402.         for (int partIndex = scoreFirstPart; partIndex < melody.part.number();
  403.           ++partIndex) {
  404.           Part &p = *((Part *) &melody.part[partIndex]);
  405.           for (int staffIndex = scoreIndex*p.multiplicity();
  406.             staffIndex < (scoreIndex+1)*p.multiplicity(); ++staffIndex) {
  407.             // Draw a single staff
  408.             Staff &s = *((Staff *) &p.staff[staffIndex]);
  409.             int tempY = s.Y();
  410.             s.Y() = line += pixelsPerStaff;
  411.             screenFull = !s.Draw(hDC, 0, TRUE);
  412.             staffX = staffLeftX;
  413.             staffY = line;
  414.  
  415.             // Draw the point objects inside the staff
  416.             IndexedList &pointList = s.pointObject;
  417.             for (int i = 0; i < pointList.number(); ++i)
  418.               ((PointObject *) &pointList[i])->Draw(hDC);
  419.  
  420.             // Draw the continuous objects inside the staff
  421.             IndexedList &contList = s.continuousObject;
  422.             for (i = 0; i < contList.number(); ++i)
  423.               ((ContinuousObject *) &contList[i])->Draw(hDC);
  424.  
  425.             s.Y() = tempY;
  426.           }
  427.         }
  428.  
  429.         // Draw the connecting lines of the score multiple staff
  430.         MoveTo(hDC, staffLeftX, line-(scoreMultiplicity-1)*pixelsPerStaff);
  431.         LineTo(hDC, staffLeftX, line+24);
  432.         MoveTo(hDC, staffRightX, line-(scoreMultiplicity-1)*pixelsPerStaff);
  433.         LineTo(hDC, staffRightX, line+24);
  434.       }
  435.  
  436.       // Display the status information
  437.       char strnum[15];
  438.       HDC hStatusDC = GetDC(hMainWnd);
  439.       HBRUSH hBrush, hOldBrush;
  440.       hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  441.       hOldBrush = SelectObject(hStatusDC, hBrush);
  442.       Rectangle(hStatusDC, 108, -1, GetSystemMetrics(SM_CXSCREEN), 37);
  443.       SetBkColor(hStatusDC, GetSysColor(COLOR_WINDOW));
  444.       SetTextAlign(hStatusDC, TA_UPDATECP);
  445.       MoveTo(hStatusDC, 110, 2);
  446.       TextOut(hStatusDC, 0, 0, "Score display, Staff ", 21);
  447.       sprintf(strnum, "%d", scoreFirstStaff+1);
  448.       TextOut(hStatusDC, 0, 0, strnum, strlen(strnum));
  449.       SelectObject(hStatusDC, hOldBrush);
  450.       DeleteObject(hBrush);
  451.       ReleaseDC(hMainWnd, hStatusDC);
  452.     }
  453.   }
  454.  
  455.   EndPaint(hWnd, &ps);
  456. }
  457.  
  458. // **********************************************
  459. // Staff::Draw is the Staff class's Draw function,
  460. // which draws a staff in a display context, returning TRUE
  461. // if the staff was not entirely clipped.
  462.  
  463. BOOL Staff :: Draw(HDC hDC, int editYMin, BOOL clip)
  464. {
  465.   int line = Y();
  466.   RECT staffRect = {0, line-editYMin, melody.GetStaffWidth(), line-editYMin+24};
  467.   RECT windowRect, dummyRect;
  468.  
  469.   // Check whether staff is within screen range
  470.   if (clip) GetClientRect(hEditWnd, &windowRect);
  471.   if (!clip || IntersectRect(&dummyRect, &staffRect, &windowRect)) {
  472.     // Either no clip checking or the staff is within clipping boundaries:
  473.     // draw the staff lines
  474.     for (; line < Y()+5*6; line += 6 ) {
  475.       MoveTo(hDC, X(), line-editYMin);
  476.       LineTo(hDC, X()+width(), line-editYMin);
  477.     }
  478.     return TRUE;
  479.   }
  480.  
  481.   return FALSE;
  482. }
  483.